package component
{
	import events.CommonStringEvent;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.MouseEvent;
	import flash.events.TextEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import mx.controls.ComboBase;
	import mx.core.ClassFactory;
	import mx.core.IFactory;
	import mx.core.LayoutDirection;
	import mx.core.UIComponentGlobals;
	import mx.core.mx_internal;
	import mx.events.CalendarLayoutChangeEvent;
	import mx.events.DateChooserEvent;
	import mx.events.DropdownEvent;
	import mx.events.FlexEvent;
	import mx.events.FlexMouseEvent;
	import mx.events.InterManagerRequest;
	import mx.events.SandboxMouseEvent;
	import mx.managers.IFocusManagerComponent;
	import mx.managers.ISystemManager;
	import mx.managers.PopUpManager;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;
	import mx.styles.StyleProxy;
	import mx.utils.ObjectUtil;
	
	import spark.formatters.DateTimeFormatter;
	
	use namespace mx_internal;
	[Event(name="change", type="mx.events.CalendarLayoutChangeEvent")]
	[Event(name="dataChange", type="mx.events.FlexEvent")]
	[Event(name="scroll", type="mx.events.DateChooserEvent")]
	
	[Style(name="borderColor", type="uint", format="Color", inherit="no", theme="halo")]
	[Style(name="borderThickness", type="Number", format="Length", inherit="no", theme="halo")]
	[Style(name="dateChooserStyleName", type="String", inherit="no")]
	[Style(name="rollOverColor", type="uint", format="Color", inherit="yes")]
	[Style(name="selectionColor", type="uint", format="Color", inherit="yes")]
	[Style(name="skin", type="Class", inherit="no", states=" up, over, down, disabled")]
	[Style(name="todayColor", type="uint", format="Color", inherit="yes")]

	//--------------------------------------
	//  Other metadata
	//--------------------------------------
	
	[DefaultBindingProperty(source="selectedDate", destination="selectedDate")]
	[DefaultTriggerEvent("change")]
	[RequiresDataBinding(true)]
	public class DateTimeField extends ComboBase
	{
		[Embed(source="assets/CalendarIcon.png")]
		private var calicon:Class;
		
		private var dtfTime:DateTimeFormatter;
		public function DateTimeField()
		{
			super();
			this.dayNames=["日","一","二","三","四","五","六"];
			this.monthNames=["一","二","三","四","五","六","七","八","九","十","十一","十二"];
			this.yearNavigationEnabled = true;
			
			dtfTime = new DateTimeFormatter();
			dtfTime.dateTimePattern = "yyyy-MM-dd HH:mm:ss";
		}
		
		public static function stringToDate(valueString:String, inputFormat:String):Date
		{
			var mask:String
			var temp:String;
			var dateString:String = "";
			var monthString:String = "";
			var yearString:String = "";
			var j:int = 0;
			
			var n:int = inputFormat.length;
			for (var i:int = 0; i < n; i++,j++)
			{
				temp = "" + valueString.charAt(j);
				mask = "" + inputFormat.charAt(i);
				
				if (mask == "M")
				{
					if (isNaN(Number(temp)) || temp == " ")
						j--;
					else
						monthString += temp;
				}
				else if (mask == "D")
				{
					if (isNaN(Number(temp)) || temp == " ")
						j--;
					else
						dateString += temp;
				}
				else if (mask == "Y")
				{
					yearString += temp;
				}
				else if (!isNaN(Number(temp)) && temp != " ")
				{
					return null;
				}
			}
			
			temp = "" + valueString.charAt(inputFormat.length - i + j);
			if (!(temp == "") && (temp != " "))
				return null;
			
			var monthNum:Number = Number(monthString);
			var dayNum:Number = Number(dateString);
			var yearNum:Number = Number(yearString);
			
			if (isNaN(yearNum) || isNaN(monthNum) || isNaN(dayNum))
				return null;
			
			if (yearString.length == 2 && yearNum < 70)
				yearNum+=2000;
			
			var newDate:Date = new Date(yearNum, monthNum - 1, dayNum);
			
			if (dayNum != newDate.getDate() || (monthNum - 1) != newDate.getMonth())
				return null;
			
			return newDate;
		}


		private var creatingDropdown:Boolean = false;
		mx_internal var showingDropdown:Boolean = false;
		private var inKeyDown:Boolean = false;
		private var isPressed:Boolean;
		private var openPos:Number = 0;
		private var lastSelectedDate:Date;
		private var updateDateFiller:Boolean = false;
		private var addedToPopupManager:Boolean = false;
		private var isMouseOver:Boolean = false;
		private var yearChangedWithKeys:Boolean = false;
		private var selectedDateSet:Boolean;
		private var _enabled:Boolean = true;
		private var enabledChanged:Boolean = false;
		
		[Bindable("enabledChanged")]
		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
		override public function get enabled():Boolean
		{
			return _enabled;
		}
		
		override public function set enabled(value:Boolean):void
		{
			if (value == _enabled)
				return;
			
			_enabled = value;
			super.enabled = value;
			enabledChanged = true;
			
			invalidateProperties();
		}
		
		private var _data:Object;
		
		[Bindable("dataChange")]
		[Inspectable(environment="none")]
		public function get data():Object
		{
			return _data;
		}

		public function set data(value:Object):void
		{
			var newDate:Date;
			_data = value;
			
			if (_data is String)
				newDate = new Date(Date.parse(data as String));
			else
				newDate = _data as Date;
			
			if (!selectedDateSet)
			{
				selectedDate = newDate;
				selectedDateSet = false;
			}
			
			dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
		}
		

		private var _dayNames:Array;
		private var dayNamesChanged:Boolean = false;
		private var dayNamesOverride:Array;
		
		[Bindable("dayNamesChanged")]
		[Inspectable(arrayType="String", defaultValue="null")]
		
		public function get dayNames():Array
		{
			return _dayNames;
		}
		
		public function set dayNames(value:Array):void
		{
			dayNamesOverride = value;
			
			_dayNames = value != null ?
				value :
				resourceManager.getStringArray(
					"controls", "dayNamesShortest");
			
			_dayNames = _dayNames ? _dayNames.slice(0) : null;
			
			dayNamesChanged = true;
			
			invalidateProperties();
		}
		
		private var _disabledDays:Array = [];
		private var disabledDaysChanged:Boolean = false;
		
		[Bindable("disabledDaysChanged")]
		[Inspectable(arrayType="int")]
		
		public function get disabledDays():Array
		{
			return _disabledDays;
		}
		
		/**
		 *  @private
		 */
		public function set disabledDays(value:Array):void
		{
			_disabledDays = value;
			disabledDaysChanged = true;
			updateDateFiller = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  disabledRanges
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the disabledRanges property.
		 */
		private var _disabledRanges:Array = [];
		
		/**
		 *  @private
		 */
		private var disabledRangesChanged:Boolean = false;
		
		[Bindable("disabledRangesChanged")]
		[Inspectable(arrayType="Object")]
		
		public function get disabledRanges():Array
		{
			return _disabledRanges;
		}
		
		/**
		 *  @private
		 */
		public function set disabledRanges(value:Array):void
		{
			_disabledRanges = scrubTimeValues(value);
			disabledRangesChanged = true;
			updateDateFiller = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  displayedMonth
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the displayedMonth property.
		 */
		private var _displayedMonth:int = (new Date()).month;
		
		/**
		 *  @private
		 */
		private var displayedMonthChanged:Boolean = false;
		
		[Bindable("displayedMonthChanged")]
		[Inspectable(category="General")]
		
		public function get displayedMonth():int
		{
			if (dropdown && dropdown.displayedMonth != _displayedMonth)
				return dropdown.displayedMonth;
			else
				return _displayedMonth;
		}
		
		/**
		 *  @private
		 */
		public function set displayedMonth(value:int):void
		{
			_displayedMonth = value;
			displayedMonthChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  displayedYear
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the displayedYear property.
		 */
		private var _displayedYear:int = (new Date()).fullYear;
		
		/**
		 *  @private
		 */
		private var displayedYearChanged:Boolean = false;
		
		[Bindable("displayedYearChanged")]
		[Inspectable(category="General")]
		public function get displayedYear():int
		{
			if (dropdown && dropdown.displayedYear != _displayedYear)
				return dropdown.displayedYear;
			else
				return _displayedYear;
		}
		
		/**
		 *  @private
		 */
		public function set displayedYear(value:int):void
		{
			_displayedYear = value;
			displayedYearChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  dropdown
		//----------------------------------
		private var _dropdown:TimeChooser;
		public function get dropdown():TimeChooser
		{
			return _dropdown;
		}
		
		//----------------------------------
		//  dropdownFactory
		//----------------------------------
		private var _dropdownFactory:IFactory = new ClassFactory(TimeChooser);
		private var _firstDayOfWeek:Object
		private var firstDayOfWeekChanged:Boolean = false;
		
		[Bindable("firstDayOfWeekChanged")]
		[Inspectable(defaultValue="0")]
		
		/**
		 *  @private
		 */
		private var firstDayOfWeekOverride:Object;
		public function get firstDayOfWeek():Object
		{
			return _firstDayOfWeek;
		}
		
		/**
		 *  @private
		 */
		public function set firstDayOfWeek(value:Object):void
		{
			firstDayOfWeekOverride = value;
			
			_firstDayOfWeek = value != null ?
				int(value) :
				resourceManager.getInt(
					"controls", "firstDayOfWeek");
			
			firstDayOfWeekChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  formatString
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the formatString property.
		 */
		private var _formatString:String = "yyyy-MM-dd HH:mm:ss";
		[Bindable("formatStringChanged")]
		[Inspectable(defaultValue="null")]
		private var formatStringOverride:String;
		public function get formatString():String
		{
			return _formatString;
		}
		
		/**
		 *  @private
		 */
		public function set formatString(value:String):void
		{
			formatStringOverride = value;
			
			_formatString = value != null ?
				value :
				resourceManager.getString(
					"SharedResources", "dateFormat");
			
			updateDateFiller = true;
			
			invalidateProperties();
			invalidateSize();
			
			dispatchEvent(new Event("formatStringChanged"));
		}
		
		//----------------------------------
		//  labelFunction
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the labelFunction property.
		 */
		private var _labelFunction:Function;
		
		[Bindable("labelFunctionChanged")]
		[Inspectable(category="Data")]
		public function get labelFunction():Function
		{
			return _labelFunction;
		}
		
		/**
		 *  @private
		 */
		public function set labelFunction(value:Function):void
		{
			_labelFunction = value;
			updateDateFiller = true;
			
			invalidateProperties();
			
			dispatchEvent(new Event("labelFunctionChanged"));
		}
		
		//----------------------------------
		//  maxYear
		//----------------------------------
		
		private var _maxYear:int = 2100;
		private var maxYearChanged:Boolean = false;
		public function get maxYear():int
		{
			if (dropdown)
				return dropdown.maxYear;
			else
				return _maxYear;
		}
		
		/**
		 *  @private
		 */
		public function set maxYear(value:int):void
		{
			if (_maxYear == value)
				return;
			
			_maxYear = value;
			maxYearChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  minYear
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the minYear property.
		 */
		private var _minYear:int = 1900;
		private var minYearChanged:Boolean = false;
		public function get minYear():int
		{
			if (dropdown)
				return dropdown.minYear;
			else
				return _minYear;
		}
		
		/**
		 *  @private
		 */
		public function set minYear(value:int):void
		{
			if (_displayedYear == value)
				return;
			
			_minYear = value;
			minYearChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  monthNames
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the monthNames property.
		 */
		private var _monthNames:Array;
		
		/**
		 *  @private
		 */
		private var monthNamesChanged:Boolean = false;
		
		/**
		 *  @private
		 */
		private var monthNamesOverride:Array;
		
		[Bindable("monthNamesChanged")]
		[Inspectable(category="Other", arrayType="String", defaultValue="null")]
		public function get monthNames():Array
		{
			return _monthNames;
		}
		
		/**
		 *  @private
		 */
		public function set monthNames(value:Array):void
		{
			monthNamesOverride = value;
			
			_monthNames = value != null ?
				value :
				resourceManager.getStringArray(
					"SharedResources", "monthNames");
			
			// _monthNames will be null if there are no resources.
			_monthNames = _monthNames ? _monthNames.slice(0) : null;
			
			monthNamesChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  parseFunction
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the parseFunction property.
		 */
		private var _parseFunction:Function = stringToDate;
		
		[Bindable("parseFunctionChanged")]
		public function get parseFunction():Function
		{
			return _parseFunction;
		}
		
		public function set parseFunction(value:Function):void
		{
			_parseFunction = value;
			
			dispatchEvent(new Event("parseFunctionChanged"));
		}
		
		//----------------------------------
		//  selectableRange
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the selectableRange property.
		 */
		private var _selectableRange:Object = null;
		
		/**
		 *  @private
		 */
		private var selectableRangeChanged:Boolean = false;
		
		[Bindable("selectableRangeChanged")]
		[Inspectable(arrayType="Date")]
		
		public function get selectableRange():Object
		{
			return _selectableRange;
		}
		
		/**
		 *  @private
		 */
		public function set selectableRange(value:Object):void
		{
			_selectableRange = scrubTimeValue(value);
			selectableRangeChanged = true;
			updateDateFiller = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  selectedDate
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the selectedDate property.
		 */
		private var _selectedDate:Date = null;
		
		/**
		 *  @private
		 */
		private var selectedDateChanged:Boolean = false;
		
		[Bindable("change")]
		[Bindable("valueCommit")]
		[Bindable("selectedDateChanged")]
		[Inspectable(category="General")]
		public function get selectedDate():Date
		{
			return _selectedDate;
		}
		
		/**
		 *  @private
		 */
		public function set selectedDate(value:Date):void
		{
			if (ObjectUtil.dateCompare(_selectedDate, value) == 0) 
				return;
			
			selectedDateSet = true;
			_selectedDate = scrubTimeValue(value) as Date;
			updateDateFiller = true;
			selectedDateChanged = true;
			
			invalidateProperties();
			
			// Trigger bindings to 'selectedData'.
			dispatchEvent(new Event("selectedDateChanged"));
			
			dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));    
		}
		
		//----------------------------------
		//  showToday
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the showToday property.
		 */
		private var _showToday:Boolean = true;
		
		/**
		 *  @private
		 */
		private var showTodayChanged:Boolean = false;
		
		[Bindable("showTodayChanged")]
		[Inspectable(category="General", defaultValue="true")]
		
		public function get showToday():Boolean
		{
			return _showToday;
		}
		
		/**
		 *  @private
		 */
		public function set showToday(value:Boolean):void
		{
			_showToday = value;
			showTodayChanged = true;
			
			invalidateProperties();
		}
		
		//----------------------------------
		//  yearNavigationEnabled
		//----------------------------------
		
		/**
		 *  @private
		 *  Storage for the yearNavigationEnabled property.
		 */
		private var _yearNavigationEnabled:Boolean = false;
		
		/**
		 *  @private
		 */
		private var yearNavigationEnabledChanged:Boolean = false;
		
		[Bindable("yearNavigationEnabledChanged")]
		[Inspectable(defaultValue="false")]
		
		public function get yearNavigationEnabled():Boolean
		{
			return _yearNavigationEnabled;
		}
		
		/**
		 *  @private
		 */
		public function set yearNavigationEnabled(value:Boolean):void
		{
			_yearNavigationEnabled = value;
			yearNavigationEnabledChanged = true;
			
			invalidateProperties();
		}
	
		override protected function createChildren():void
		{
			super.createChildren();
			
			createDropdown();
			
			downArrowButton.setStyle("disabledSkin",calicon);
			downArrowButton.setStyle("downSkin",calicon);
			downArrowButton.setStyle("overSkin",calicon);
			downArrowButton.setStyle("upSkin", calicon);
			
			textInput.editable = false;
			textInput.mouseChildren = true;
			textInput.mouseEnabled = true;
			// hide the border, we use the text input's border
			if (border)
				border.visible = false;
			
		}
		
		/**
		 *  @private
		 */
		override protected function commitProperties():void
		{
			if (enabledChanged)
			{
				enabledChanged = false;
				dispatchEvent(new Event("enabledChanged"));
			}
			
			if (dayNamesChanged)
			{
				dayNamesChanged = false;
				// _dayNames will be null if there are no resources.
				dropdown.dayNames = _dayNames ? _dayNames.slice(0) : null;
				dispatchEvent(new Event("dayNamesChanged"));
			}
			
			if (disabledDaysChanged)
			{
				disabledDaysChanged = false;
				dropdown.disabledDays = _disabledDays.slice(0);
				dispatchEvent(new Event("disabledDaysChanged"));
			}
			
			if (disabledRangesChanged)
			{
				disabledRangesChanged = false;
				dropdown.disabledRanges = _disabledRanges.slice(0);
				dispatchEvent(new Event("disabledRangesChanged"));
			}
			
			if (displayedMonthChanged)
			{
				displayedMonthChanged = false;
				dropdown.displayedMonth = _displayedMonth;
				dispatchEvent(new Event("displayedMonthChanged"));
			}
			
			if (displayedYearChanged)
			{
				displayedYearChanged = false;
				dropdown.displayedYear = _displayedYear;
				dispatchEvent(new Event("displayedYearChanged"));
			}
			
			if (firstDayOfWeekChanged)
			{
				firstDayOfWeekChanged = false;
				dropdown.firstDayOfWeek = _firstDayOfWeek;
				dispatchEvent(new Event("firstDayOfWeekChanged"));
			}
			
			if (minYearChanged)
			{
				minYearChanged = false;
				dropdown.minYear = _minYear;
			}
			
			if (maxYearChanged)
			{
				maxYearChanged = false;
				dropdown.maxYear = _maxYear;
			}
			
			if (monthNamesChanged)
			{
				monthNamesChanged = false;
				// _monthNames will be null if there are no resources.
				dropdown.monthNames = _monthNames ? _monthNames.slice(0) : null;
				dispatchEvent(new Event("monthNamesChanged"));
			}
			
			if (selectableRangeChanged)
			{
				selectableRangeChanged = false;
				dropdown.selectableRange = _selectableRange is Array ? _selectableRange.slice(0) : _selectableRange;
				dispatchEvent(new Event("selectableRangeChanged"));
			}
			
			if (selectedDateChanged)
			{
				selectedDateChanged = false;
				dropdown.selectedDate = _selectedDate;
			}
			
			if (showTodayChanged)
			{
				showTodayChanged = false;
				dropdown.showToday = _showToday;
				dispatchEvent(new Event("showTodayChanged"));
			}
			
			if (updateDateFiller)
			{
				updateDateFiller = false;
				dateFiller(_selectedDate);
			}
			
			if (yearNavigationEnabledChanged)
			{
				yearNavigationEnabledChanged = false;
				dropdown.yearNavigationEnabled = _yearNavigationEnabled;
				dispatchEvent(new Event("yearNavigationEnabledChanged"));
			}
			
			super.commitProperties();
		}
		
		/**
		 *  @private
		 */
		override protected function measure():void
		{
			// skip base class, we do our own calculation here
			// super.measure();
			
			var buttonWidth:Number = downArrowButton.getExplicitOrMeasuredWidth();
			var buttonHeight:Number = downArrowButton.getExplicitOrMeasuredHeight();
			
			var bigDate:Date = new Date(2004, 12, 31);
			var txt:String = (_labelFunction != null) ? _labelFunction(bigDate) : 
				dtfTime.format(bigDate);
			
			measuredMinWidth = measuredWidth = measureText(txt).width + 8 + 2 + buttonWidth;
			measuredMinWidth = measuredWidth += getStyle("paddingLeft") + getStyle("paddingRight");
			measuredMinHeight = measuredHeight = textInput.getExplicitOrMeasuredHeight();
		}
		
		/**
		 *  @private
		 */
		override protected function updateDisplayList(unscaledWidth:Number,
													  unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			var w:Number = unscaledWidth;
			var h:Number = unscaledHeight;
			
			var arrowWidth:Number = downArrowButton.getExplicitOrMeasuredWidth();
			var arrowHeight:Number = downArrowButton.getExplicitOrMeasuredHeight();
			
			downArrowButton.setActualSize(arrowWidth, arrowHeight);
			downArrowButton.move(w - arrowWidth, Math.round((h - arrowHeight) / 2));
			
			textInput.setActualSize(w - arrowWidth - 2, h);
		}
		
		/**
		 *  @private
		 */
		override public function regenerateStyleCache(recursive:Boolean):void
		{
			super.regenerateStyleCache(recursive);
			
			if (dropdown)
				dropdown.regenerateStyleCache(recursive);
		}
		/**
		 *  @private
		 */
		private function displayDropdown(show:Boolean, triggerEvent:Event = null):void
		{
			if (!_enabled)
				return;
			
			if (show == showingDropdown)
				return;
			
			if (!addedToPopupManager)
			{
				addedToPopupManager = true;
				PopUpManager.addPopUp(_dropdown, this, false);
			}
			else
				PopUpManager.bringToFront(_dropdown);
			
			// Subclasses may extend to do pre-processing
			// before the dropdown is displayed
			// or override to implement special display behavior.
			//var point = {};
			// point x will exactly appear on the icon.
			// Leaving 1 pixel for the border to appear.
			var xPos:Number = (layoutDirection == LayoutDirection.RTL ? 
				dropdown.getExplicitOrMeasuredWidth() : 0) 
				+ unscaledWidth - downArrowButton.width; 
			
			var point:Point = new Point(xPos, 0);
			point = localToGlobal(point);
			if (show)
			{
				if (_parseFunction != null)
					_selectedDate = _parseFunction(text, formatString);
				lastSelectedDate = _selectedDate;
				selectedDate_changeHandler(triggerEvent);
				
				var dd:TimeChooser = dropdown;
				
				if (_dropdown.selectedDate)
				{
					_dropdown.displayedMonth = _dropdown.selectedDate.getMonth();
					_dropdown.displayedYear = _dropdown.selectedDate.getFullYear();
				}
				dd.visible = show;
				dd.scaleX = scaleX;
				dd.scaleY = scaleY;
				
				var xVal:Number = point.x;
				var yVal:Number = point.y;
				
				//handling of dropdown position
				// A. Bottom Left Placment
				// B. Bottom Right Placement
				// C. Top Right Placement
				var sm:ISystemManager = systemManager.topLevelSystemManager;
				var screen:Rectangle = sm.getVisibleApplicationRect(null, true);
				
				if (screen.right > dd.getExplicitOrMeasuredWidth() + point.x &&
					screen.bottom < dd.getExplicitOrMeasuredHeight() + point.y)
				{
					xVal = point.x
					yVal = point.y - dd.getExplicitOrMeasuredHeight();
					openPos = 1;
				}
				else if (screen.right < dd.getExplicitOrMeasuredWidth() + point.x &&
					screen.bottom < dd.getExplicitOrMeasuredHeight() + point.y)
				{
					xVal = point.x - dd.getExplicitOrMeasuredWidth() + downArrowButton.width;
					yVal = point.y - dd.getExplicitOrMeasuredHeight();
					openPos = 2;
				}
				else if (screen.right < dd.getExplicitOrMeasuredWidth() + point.x &&
					screen.bottom > dd.getExplicitOrMeasuredHeight() + point.y)
				{
					xVal = point.x - dd.getExplicitOrMeasuredWidth() + downArrowButton.width;
					yVal = point.y + unscaledHeight;
					openPos = 3;
				}
				else
					// Why do we need to disable downArrowButton when its hidden?
					//downArrowButton.enabled = false;
					openPos = 0;
				
				xVal = Math.max(screen.left, xVal);
				
				point.x = xVal;
				point.y = yVal;
				point = dd.parent.globalToLocal(point);
				UIComponentGlobals.layoutManager.validateClient(dd, true);
				dd.move(point.x, point.y);
				Object(dd).setActualSize(dd.getExplicitOrMeasuredWidth(),dd.getExplicitOrMeasuredHeight());
				
			}
			else
			{
				_dropdown.visible = false;
			}
			
			showingDropdown = show;
		}
		
		/**
		 *  @private
		 */
		private function createDropdown():void
		{
			if (creatingDropdown)
				return;
			
			creatingDropdown = true;
			
			_dropdown = _dropdownFactory.newInstance();
			_dropdown.focusEnabled = false;
			_dropdown.owner = this;
			_dropdown.moduleFactory = moduleFactory;
			var todaysDate:Date = new Date();
			_dropdown.displayedMonth = todaysDate.getMonth();
			_dropdown.displayedYear = todaysDate.getFullYear();
			
			_dropdown.styleName = new StyleProxy(this, {}); 
			
			var dateChooserStyleName:Object = getStyle("dateChooserStyleName");
			if (dateChooserStyleName)
			{
				var styleDecl:CSSStyleDeclaration =
					styleManager.getMergedStyleDeclaration("." + dateChooserStyleName);
				
				if (styleDecl)
					_dropdown.styleDeclaration = styleDecl;
			}
			
			_dropdown.visible = false;
			
			_dropdown.addEventListener(CalendarLayoutChangeEvent.CHANGE,dropdown_changeHandler);
			_dropdown.addEventListener("buttonclick",dropdown_buttonclickHandler);
			_dropdown.addEventListener(DateChooserEvent.SCROLL,
				dropdown_scrollHandler);
			_dropdown.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE,
				dropdown_mouseDownOutsideHandler);
			_dropdown.addEventListener(FlexMouseEvent.MOUSE_WHEEL_OUTSIDE,
				dropdown_mouseDownOutsideHandler);
			_dropdown.addEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE,
				dropdown_mouseDownOutsideHandler);
			_dropdown.addEventListener(SandboxMouseEvent.MOUSE_WHEEL_SOMEWHERE,
				dropdown_mouseDownOutsideHandler);
			
			creatingDropdown = false;
		}
		
		private function dateFiller(value:Date):void
		{
			if (_labelFunction != null)
				textInput.text = labelFunction(value);
			else
				textInput.text = dtfTime.format(value);
		}
		
		/**
		 *  @private
		 *  This method scrubs out time values from incoming date objects
		 */ 
		private function scrubTimeValue(value:Object):Object
		{
			if (value is Date)
			{
				return new Date(value.getFullYear(), value.getMonth(), value.getDate());
			}
			else if (value is Object) 
			{
				var range:Object = {};
				if (value.rangeStart)
				{
					range.rangeStart = new Date(value.rangeStart.getFullYear(), 
						value.rangeStart.getMonth(), 
						value.rangeStart.getDate());
				}
				
				if (value.rangeEnd)
				{
					range.rangeEnd = new Date(value.rangeEnd.getFullYear(), 
						value.rangeEnd.getMonth(), 
						value.rangeEnd.getDate());
				}
				return range;
			}
			return null;
		}
		
		/**
		 *  @private
		 *  This method scrubs out time values from incoming date objects
		 */ 
		private function scrubTimeValues(values:Array):Array
		{
			var dates:Array = [];
			for (var i:int = 0; i < values.length; i++)
			{
				dates[i] = scrubTimeValue(values[i]);
			}
			return dates;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Overridden event handlers: UIComponent
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  @private
		 */
		override protected function focusOutHandler(event:FocusEvent):void
		{
			if (showingDropdown && event != null &&
				!this.contains(DisplayObject(event.target)))
				displayDropdown(false);
			
			super.focusOutHandler(event);
			
			if (_parseFunction != null)
				_selectedDate = _parseFunction(text, formatString);
			
			selectedDate_changeHandler(event);
		}
		
		/**
		 *  @private
		 */
		override protected function downArrowButton_buttonDownHandler(
			event:FlexEvent):void
		{
			// The down arrow should always toggle the visibility of the dropdown.
			callLater(displayDropdown, [ !showingDropdown, event ]);
		}

		//--------------------------------------------------------------------------
		//
		//  Event handlers
		//
		//--------------------------------------------------------------------------
		
		/**
		 *  @private
		 */
		private function removedFromStageHandler(event:Event):void
		{
			// Ensure we've unregistered ourselves from PopupManager, else
			// we'll be leaked.
			addedToPopupManager = false;
			PopUpManager.removePopUp(_dropdown);
		}
		
		/**
		 *  @private
		 */
		private function dropdown_changeHandler( event:CalendarLayoutChangeEvent):void
		{
			if (ObjectUtil.dateCompare(_selectedDate, dropdown.selectedDate) == 0)
				return;
			
			_selectedDate = dropdown.selectedDate;
			
			if (_selectedDate)
				dateFiller(_selectedDate);
			else
				textInput.text = "";
			
			var e:CalendarLayoutChangeEvent = new 
				CalendarLayoutChangeEvent(CalendarLayoutChangeEvent.CHANGE);        
			e.newDate = event.newDate;
			e.triggerEvent = event.triggerEvent;
			dispatchEvent(e);                   
		}
		
		/**
		 *  @private
		 */
		private function dropdown_scrollHandler(event:DateChooserEvent):void
		{
			dispatchEvent(event);
		}
		
		/**
		 *  @private
		 */
		private function dropdown_mouseDownOutsideHandler(event:Event):void
		{
			if (event is MouseEvent)
			{
				var mouseEvent:MouseEvent = MouseEvent(event);
				
				if (! hitTestPoint(mouseEvent.stageX, mouseEvent.stageY, true))
					displayDropdown(false, event);
			}
		}
		
		private function dropdown_buttonclickHandler(event:CommonStringEvent):void
		{
			if(event.innerText =="确定")
			{
				_selectedDate = dropdown.selectedDate;
				
				if (_selectedDate)
					dateFiller(_selectedDate);
				else
					textInput.text = "";
				displayDropdown(false);
				
				var e:CalendarLayoutChangeEvent = new 
					CalendarLayoutChangeEvent(CalendarLayoutChangeEvent.CHANGE);        
				//e.newDate = event.newDate;
				//e.triggerEvent = event.triggerEvent;
				dispatchEvent(e); 
				
			}
			else if(event.innerText =="清空")
			{
				textInput.text = "";
				this.selectedDate = null;
				displayDropdown(false);
			}
			else if(event.innerText =="现在")
			{
				var nowDate:Date = new Date();
				//this.selectedDate = nowDate;
				textInput.text = dtfTime.format(nowDate);
				displayDropdown(false);
			}
		}
		
		/**
		 *  @private
		 *  Handling change in selectedDate due to user interaction.
		 */
		private function selectedDate_changeHandler(triggerEvent:Event):void
		{
			if (!dropdown.selectedDate && !_selectedDate)
				return;
			
			if (_selectedDate)
				dateFiller(_selectedDate);
			
			if (dropdown.selectedDate && _selectedDate &&
				dropdown.selectedDate.getFullYear() == _selectedDate.getFullYear() &&
				dropdown.selectedDate.getMonth() == _selectedDate.getMonth() &&
				dropdown.selectedDate.getDate() == _selectedDate.getDate())
				return;
			
			dropdown.selectedDate = _selectedDate;
			
			var changeEvent:CalendarLayoutChangeEvent =
				new CalendarLayoutChangeEvent(CalendarLayoutChangeEvent.CHANGE);
			changeEvent.newDate = _selectedDate;
			changeEvent.triggerEvent = triggerEvent;
			dispatchEvent(changeEvent);
		}
	}
}
